---------------------------------------------------------------------------------
  -- Design Name : work.UserPkg.GenAdd32 Test Bench
  -- File Name   : GenAdd32.vht
  -- Function    : work.UserPkg.GenAdd32 test bench
  -- Authors     : Mirko Francuski  2006/0225
  --               Milos Mihajlovic 2006/0039
  -- School      : University of Belgrade
  --               School for Electrical Engineering
  --               Department for Computer Engineering and Information Theory
  -- Subject     : VLSI Computer Systems
---------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_textio.all;
use ieee.numeric_std.all;
use std.textio.all;
use work.TBPkg.all;
use work.UserPkg.all;

entity CPU_vhd_tst is
  -- this page is intentionally left blank
end CPU_vhd_tst;

architecture CPU_arch of CPU_vhd_tst is
  -- constants
  constant DATA_MEM_SIZE2 : integer := 300;
  constant INSTR_MEM_SIZE : integer := 128;
  -- type
  type TDataMem is array(0 to DATA_MEM_SIZE2 - 1) of word32;
  type TInstrMem is array(0 to INSTR_MEM_SIZE - 1) of word32;
  -- signals
  signal clk      : std_logic;
  signal start    : std_logic;
  signal reset    : std_logic;
  signal iRd      : std_logic;
  signal dRd      : std_logic;
  signal dWr      : std_logic;
  signal diBUS    : Word32;
  signal aiBUS    : Word32;
  signal adBUS    : Word32;
  signal ddBUS    : Word32;
  
  --constant TESTPATH   : string := TESTPUBLIC;
  constant TESTPATH   : string := TESTBRANCH;
  --constant TESTPATH   : string := TESTHAZARDS;
  --constant TESTPATH   : string := TESTJSR;
  --constant TESTPATH   : string := TESTINST;
  constant instr_file : string := "test/" & TESTPATH & "/test_inst.txt";
  constant data_file  : string := "test/" & TESTPATH & "/test_data.txt";
  constant exp_file   : string := "test/" & TESTPATH & "/exp.txt";
    
  signal halt     : std_logic;
  signal InstrMem : TInstrMem := (others => "00000000000000000000000000000000");
  signal DataMem  : TDataMem := (others => "00000000000000000000000000000000");
  
  file exp        : text is exp_file;
  file data       : text is data_file;
  file instr      : text is instr_file;
begin
  
  Clock_inst : Clock port map (
    clk => clk
  );
  
  CPU_inst : CPU port map (
    -- list connections between master ports and signals
    clock   => clk,
    start   => start,
    reset   => reset,
    halt    => halt,
    diBUS   => diBUS,
    iRd     => iRd,
    dRd     => dRd,
    dWr     => dWr,
    aiBUS   => aiBUS,
    adBUS   => adBUS,
    ddBUS   => ddBUS
  );
  
  init : process
    -- variable declarations  
    variable ln     : line;
    variable saddr  : Word32;
    variable sdata  : string(1 to 32);
    variable blank  : string(1 to 1);
    variable adr    : integer;
  begin
    -- code that executes only once
    -- load instruction memory
    while not endfile(instr) loop
      readline(instr, ln);
      hread(ln, saddr);
      read(ln, blank);
      read(ln, sdata);
      adr := to_integer(unsigned(saddr));
      report "      ==  saddr  " & integer'image(adr);
      report "      ==  sdata  " & sdata;
      InstrMem(adr) <= to_std_logic_vector(sdata);
    end loop;
    
    wait;                                 -- stop running
  end process init;
  
  always : process
    -- optional sensitivity list
    -- (        )
    -- variable declarations
    variable readInstr : boolean := false;
    variable readData : boolean := false;
    variable writeData : boolean := false;
    
    variable iAddr : Integer;
    variable dAddr : Integer;
    variable dData : Word32;
    
    variable ln     : line;
    variable saddr  : Word32;
    variable wdata  : Word32;
    variable sdata  : string(1 to 32);
    variable blank  : string(1 to 1);
    variable adr    : integer;
  begin
    -- code executes for every event on sensitivity list
    report "Testing...";
    -- main part
    
    -- load data memory
    while not endfile(data) loop
      readline(data, ln);
      hread(ln, saddr);
      read(ln, blank);
      read(ln, sdata);
      adr := to_integer(unsigned(saddr));
      report "      ==  saddr  == " & integer'image(adr);
      report "      ==  sdata  == " & sdata;
      DataMem(adr) <= to_std_logic_vector(sdata);
    end loop;
    
    aiBUS <= (others => 'Z');
    diBUS <= (others => 'Z');
    adBUS <= (others => 'Z');
    ddBUS <= (others => 'Z');
    
    reset <= '0';
    start <= '1';
    wait until clk = '1';
    wait until clk = '1';
    start <= '0';
    while halt /= '1' loop
      
      if not (writeData or readData) then
        ddBUS <= (others => 'Z');
      end if;
      
      if readInstr then
        diBUS <= InstrMem(iAddr);
        readInstr := false;
      else  
        diBUS <= (others => 'Z');
      end if;
      if readData then
        ddBUS <= DataMem(dAddr);
        readData := false;
      end if;
      if writeData then
        DataMem(dAddr) <= dData;
        writeData := false;
      end if;
      
      wait until clk = '0';
      
      if iRd = '1' then
        readInstr := true;
        iAddr := to_integer(unsigned(aiBUS));
      end if;
      if dRd = '1' then
        readData := true;
        dAddr := to_integer(unsigned(adBUS));
      end if;
      if dWr = '1' then
        writeData := true;
        dAddr := to_integer(unsigned(adBUS));
        dData := ddBUS;   
      end if;
      
      wait until clk = '1';

    end loop;
    
    -- load and check if expected result was produced
    while not endfile(exp) loop
      readline(exp, ln);
      hread(ln, saddr);
      read(ln, blank);
      read(ln, sdata);
      adr := to_integer(unsigned(saddr));
      if unsigned(to_std_logic_vector(sdata)) = unsigned(DataMem(adr)) then
        report "Expectation met." severity note;
      else
        report "Expectation not met." severity note;
      end if;
    end loop;
    
    assert false report "Testing done." severity failure;
    wait;                                 -- stop running
  end process always;
end CPU_arch;

configuration CPU_vhd_cfg of CPU_vhd_tst is 
	for CPU_arch
    -- this page is intentionally left blank too
	end for;
end CPU_vhd_cfg;